package ch.zhaw.cctd.domain.match;

import java.awt.Point;
import java.awt.Rectangle;
import java.io.Serializable;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.zhaw.cctd.domain.player.Player;
import ch.zhaw.cctd.domain.player.RessourceException;
import ch.zhaw.cctd.domain.prototype.Prototype;
import ch.zhaw.cctd.domain.prototype.PrototypeList;
import ch.zhaw.cctd.domain.prototype.TowerPrototype;
import ch.zhaw.cctd.domain.tower.TowerBuildException;
import ch.zhaw.cctd.logic.event.EventHandler;
import ch.zhaw.cctd.logic.network.RemoteClient;
import ch.zhaw.cctd.logic.network.RemoteServer;

/**
 * Zuständig als Schnittstelle zum RMI. Sie fängt lokale calls ab und
 * beantwortet sie direkt, wenn kein refresh vom Server nötig ist. Sie versteckt
 * das Player Objekt vom UI.
 * 
 * @author Rolf Koch
 * @version 1.0
 */
public class MatchClient extends UnicastRemoteObject implements RemoteClient, Serializable {

	/**
	 * Serializable ID
	 */
	private static final long serialVersionUID = 7610171957089519055L;

	/**
	 * Logger
	 */
	private static final Logger logger = LoggerFactory.getLogger(MatchClient.class);

	// Prototype List (Handled Locally)
	private PrototypeList prototypes;

	// Eventhandler
	private EventHandler eventhandler;

	// MatchServer
	private RemoteServer server;

	// Local Player Object
	private Player localPlayer;

	/**
	 * Getter for LocalPlayer
	 * @return
	 */
	public Player getLocalPlayer() {
		return localPlayer;
	}


	/**
	 * Default Constructor
	 * 
	 * @throws RemoteException
	 */
	public MatchClient() throws RemoteException {
		super();
		logger.trace("Empty Match Client create");
	}

	
	/**
	 * Initialize the Local Client with the Eventhandler, Prototype and Server
	 * 
	 * @param eventhandler
	 * @param prototypes
	 * @param server
	 */
	public void initMatchClient(EventHandler eventhandler, PrototypeList prototypes, RemoteServer server) {
		this.eventhandler = eventhandler;
		this.prototypes = prototypes;
		this.server = server;
	}

	
	/**
	 * Returns all Prototypes
	 * 
	 * @return prototypes
	 */
	public PrototypeList getPrototypeList() {
		return this.prototypes;
	}

	
	/**
	 * Returns a specific Prototype. The Prototype has to be defined by his Type
	 * and ID.
	 * 
	 * @param <T>
	 * @param c
	 * @param id
	 * @return Prototype vom entsprechenden Typ
	 */
	public <T extends Prototype> T getPrototype(Class<T> c, String id) {
		return this.prototypes.getPrototype(c, id);
	}

	
	/**
	 * Returns the EventHandler
	 * 
	 * @return
	 */
	public EventHandler getEventHandler() {
		return this.eventhandler;
	}

	
	/**
	 * Pay Money from one user to another
	 * 
	 * @param targetPlayerId
	 * @param amount
	 */
	public void ressourceTransfer(int targetPlayerId, int amount) throws RemoteException, RessourceException {
		try {
			server.ressourceTransfer(localPlayer.getPlayerId(), targetPlayerId, amount);
		} catch (RemoteException e) {
			logger.error("Error while sending Money", e);
		}
		
	}

	
	/**
	 * Clients can be Pinged by the Server and return true
	 * @return true
	 */
	@Override
	public boolean ping() throws RemoteException {
		return true;
	}


	/**
	 * Build a new Tower for the Local Player
	 * @param towerPrototype
	 * @param point
	 * @throws RessourceException
	 * @throws TowerBuildException
	 */
	public void buildTower(TowerPrototype towerPrototype, Point point) throws RessourceException, TowerBuildException {
		try {
			server.buildTower(towerPrototype, point, localPlayer.getPlayerId());
		} catch (RemoteException e) {
			logger.error("Error while creating new Tower", e);
		}
		
	}


	/**
	 * Checks if a Position is a valid Tower Location for the local Player returns the Point if its valid, returns null if its not valid
	 * @param Point Position auf der Map
	 * @return GRidPoint
	 */
	public Point isValidTowerBuildLocation(Rectangle rect) {
		try {
			return server.isValidTowerBuildLocation(rect, localPlayer.getPlayerId());
		} catch(RemoteException e) {
			logger.error("Error while validating Towerposition", e);
		}
		return null;
	}


	/**
	 * Set the Local Player ID
	 * @param clientID
	 */
	public void setPlayerID(int clientID) {
		if(localPlayer==null) {
			localPlayer = new Player();
		}
		localPlayer.setPlayerId(clientID);		
	}


	/**
	 * Set the Local Player Name
	 * @param localPlayerName
	 */
	public void setPlayerName(String localPlayerName) {
		if(localPlayer==null) {
			localPlayer = new Player();
		}
		localPlayer.setName(localPlayerName);
	}


	/**
	 * Register the new Player
	 */
	public void registerPlayer() {
		try {
			server.addPlayer(localPlayer);
		} catch(RemoteException e) {
			logger.error("Error while registering Local Player", e);
		}
		
	}


	/**
	 * Get the Local Players current Money
	 * @return
	 */
	public int getLocalPlayerMoney() {
		try {
			return server.getPlayerMoney(localPlayer.getPlayerId());
		} catch(RemoteException e) {
			logger.error("Error while getting local player Money", e);
		}
		return 0;
	}
	
}
